home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 276-300 / disk_280 / graph / graph.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  16KB  |  544 lines

  1. /*
  2.  *                 GRAPH, Version 1.00 - 4 August 1989
  3.  *
  4.  *            Copyright 1989, David Gay. All Rights Reserved.
  5.  *            This software is freely redistrubatable.
  6.  */
  7.  
  8. /* Main program */
  9.  
  10. #include <exec/types.h>
  11. #include <libraries/dos.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <math.h>
  15.  
  16. #include "graph.h"
  17. #include "file.h"
  18. #include "object.h"
  19. #include "uio.h"
  20. #include "list.h"
  21. #include "grph.h"
  22. #include "user/eval.h"
  23. #include "tracker.h"
  24.  
  25. #include <proto/exec.h>
  26. #include <proto/dos.h>
  27.  
  28. /* Gadget ids for variables requester */
  29. #define VARSLIST 2
  30. #define VARSDEL 3
  31.  
  32. const char *eval_messages[] = {
  33.     "No error",
  34.     "Syntax error",
  35.     "Out of memory",
  36.     "Right bracket expected",
  37.     "Obsolete",
  38.     "Left bracket expected",
  39.     "Function not differentiable",
  40.     "Recursion detected",
  41.     "Result not numeric"
  42. };
  43.  
  44. /* The various libraries used */
  45. struct LayersBase *LayersBase;
  46. extern struct DiskfontBase *DiskfontBase;
  47. extern struct GfxBase *GfxBase;
  48. extern struct IntuitionBase *IntuitionBase;
  49. struct ArpBase *ArpBase;
  50.  
  51. list graph_list;    /* List of graphs */
  52. context vars;       /* List of variables */
  53.  
  54. static int vars_saved = TRUE;
  55. /* Used by variable requester */
  56. static char var[VARLEN], val[EXPRLEN];
  57. static struct Gadget *valg, *delg;
  58. static struct ListInfo *var_info;
  59.  
  60. /* Inform objects that variable var has changed value. They may need to
  61.   recalculate */
  62. static void check_vars(char *var)
  63. {
  64.     struct graph *scan;
  65.     struct object *o;
  66.  
  67.     /* Variables are global ==> for all graphs, all objects */
  68.     for (scan = first(&graph_list); succ(scan); scan = succ(scan))
  69.         for (o = first(&scan->o_list); succ(o); o = succ(o))
  70.             o->var_change(o, var);
  71. }
  72.  
  73. /* Redraw all graphs (eg after variables have changed) */
  74. static void draw_all(void)
  75. {
  76.     struct graph *g;
  77.  
  78.     for (g = first(&graph_list); succ(g); g = succ(g))
  79.         draw_graph(g, TRUE);
  80. }
  81.  
  82. /* Load a graph from a file into a new graph. See file format. */
  83. static void load_file(struct graph *from)
  84. {
  85.     FILE *f;
  86.     char file[FILELEN];
  87.  
  88.     if (getfile(file, "Load graph"))
  89.         if (f = fopen(file, "r"))
  90.         {
  91.             short tag;
  92.  
  93.             if (READ(f, tag) && tag == GRAPH_TAG)
  94.             {
  95.                 struct graph *g = load_graph(from, f);
  96.  
  97.                 if (g) add_head(&graph_list, g);
  98.             }
  99.             else
  100.                 message(from, "File is not a graph", (char *)NULL);
  101.             fclose(f);
  102.         }
  103.         else
  104.             message(from, "Couldn't open file", file, (char *)NULL);
  105. }
  106.  
  107. /* Save current graph to a file. See file format. */
  108. /* TBD: Provide some default file name */
  109. static void save_file(struct graph *g)
  110. {
  111.     FILE *f;
  112.     char file[FILELEN];
  113.  
  114.     if (getfile(file, "Save graph"))
  115.         if (f = fopen(file, "w"))
  116.         {
  117.             save_graph(g, f);
  118.             fclose(f);
  119.         }
  120.         else
  121.             message(g, "Couldn't open file", file, (char *)NULL);
  122. }
  123.  
  124. /* Read variables from a file. See file format. This adds variables to the
  125.    current context, it doesn't eliminate the old ones. */
  126. static void load_variables(struct graph *from)
  127. {
  128.     FILE *f;
  129.     char file[FILELEN];
  130.  
  131.     if (getfile(file, "Load variables"))
  132.         if (f = fopen(file, "r"))
  133.         {
  134.             short tag;
  135.             int ok = FALSE;
  136.  
  137.             if (READ(f, tag) && tag == FILE_TAG) /* This is a variable file */
  138.             {
  139.                 int done = FALSE;
  140.  
  141.                 ok = TRUE;
  142.                 do /* Read all the file */
  143.                 {
  144.                     short tag;
  145.  
  146.                     if (READ(f, tag))
  147.                     {
  148.                         switch (tag)
  149.                         {
  150.                             case FILE_END:
  151.                                 done = TRUE;
  152.                                 break;
  153.                             case VAR_TAG: /* Another variable */
  154.                                 {
  155.                                     char name[VARLEN], val[EXPRLEN];
  156.  
  157.                                     if (READ(f, name) &&
  158.                                         READ(f, val) &&
  159.                                         READ(f, tag) && tag == VAR_END)
  160.                                     {
  161.                                         value vv = compile(val);
  162.  
  163.                                         if (!vv || !set_var_name(name, vv))
  164.                                             message(from, "Failed to set variab
  165. le(no memory ?)", (char *)NULL);
  166.                                         check_vars(name);
  167.                                     }
  168.                                     else
  169.                                         ok = FALSE;
  170.                                 }
  171.                                 break;
  172.                             default:
  173.                                 ok = FALSE;
  174.                                 break;
  175.                         }
  176.                     }
  177.                     else
  178.                         ok = FALSE;
  179.                 } while (!done && ok);
  180.             }
  181.             fclose(f);
  182.             if (!ok)
  183.                 message(from, "File does not contain variables", (char *)NULL);
  184.      
  185.             else draw_all();
  186.         }
  187.         else
  188.             message(from, "Couldn't open file", file, (char *)NULL);
  189. }
  190.  
  191. /* Save variables. See file format. */
  192. static void save_variables(struct graph *g)
  193. {
  194.     FILE *f;
  195.     char file[FILELEN];
  196.  
  197.     if (getfile(file, "Save variables"))
  198.         if (f = fopen(file, "w"))
  199.         {
  200.             short tag = FILE_TAG;
  201.             int ok = FALSE;
  202.  
  203.             if (WRITE(f, tag))
  204.             {
  205.                 tnode *var;
  206.  
  207.                 ok = TRUE;
  208.                 /* For all variables */
  209.                 for (var = first(&vars); ok && succ(var); var = succ(var))
  210.                 {
  211.                     short end = VAR_END;
  212.                     char name[VARLEN], expr[EXPRLEN];
  213.                     value vv = get_var_name(var->ln_Name);
  214.  
  215.                     name[VARLEN - 1] = '\0';
  216.                     strncpy(name, var->ln_Name, VARLEN - 1);
  217.                     if (vv) decompile(vv, expr, EXPRLEN);
  218.                     else expr[0] = '\0';
  219.  
  220.                     tag = VAR_TAG;
  221.  
  222.                     ok = WRITE(f, tag) &&
  223.                          WRITE(f, name) &&
  224.                          WRITE(f, expr) &&
  225.                          WRITE(f, end);
  226.                 }
  227.                 tag = FILE_END;
  228.                 if (ok) ok = WRITE(f, tag);
  229.             }
  230.             fclose(f);
  231.             if (!ok) message(g, "Error writing file", (char *)NULL);
  232.             else vars_saved = TRUE;
  233.         }
  234.         else
  235.             message(g, "Couldn't open file", file, (char *)NULL);
  236. }
  237.  
  238. /* Handle variable requester. Could it be cleaned up ??? */
  239. int vars_handler(struct Gadget *gg, ULONG class, struct Requester *req, struct
  240. graph *g)
  241. {
  242.     int id = gg->GadgetID;
  243.     int change = FALSE;     /* Has the list changed ? */
  244.     int actval = FALSE;     /* Activate variable value gadget */
  245.     int actvar = FALSE;     /*    "        "     name    "    */
  246.     int refresh = FALSE;    /* value & name gadgets have changed */
  247.     UWORD valpos, varpos;
  248.     struct Gadget *varg = ListStr(var_info); /* The lists string gadget */
  249.  
  250.     if (gg == valg) /* Value gadget message, class is always GADGETUP */
  251.     {
  252.         valpos = RemoveGList(req->RWindow, valg, 1);
  253.         varpos = RemoveGList(req->RWindow, varg, 1);
  254.         refresh = TRUE;
  255.         strip(var); /* remove blanks */
  256.         strlwr(var);
  257.         if (*var)
  258.         {
  259.             value vv = compile(val), old;
  260.  
  261.             if (eval_error != 0) /* Invalid value, allow correction */
  262.             {
  263.                 DisplayBeep(req->RWindow->WScreen);
  264.                 actval = TRUE;
  265.             }
  266.             else /* Try & set variable */
  267.             {
  268.                 if (old = get_var_name(var)) free_expr(old);
  269.                 else /* list changes, there will be an extra var */
  270.                     change = TRUE;
  271.  
  272.                 check_vars(var);
  273.                 if (!set_var_name(var, vv))
  274.                 {
  275.                     alert(g->io.win, "Couldn't create variable", NULL);
  276.                     change = FALSE;
  277.                 }
  278.                 val[0] = var[0] = '\0';
  279.                 actvar = TRUE;
  280.             }
  281.         }
  282.         else /* blank var name -- erase val */
  283.         {
  284.             DisplayBeep(req->RWindow->WScreen);
  285.             actvar = TRUE;
  286.         }
  287.     }
  288.     else if (id == VARSDEL) /* Delete selected */
  289.     {
  290.         value vv;
  291.  
  292.         valpos = RemoveGList(req->RWindow, valg, 1);
  293.         varpos = RemoveGList(req->RWindow, varg, 1);
  294.         refresh = TRUE;
  295.         strip(var);
  296.         strlwr(var);
  297.         if (*var && (vv = get_var_name(var)))
  298.         {
  299.             free_expr(vv);
  300.             free_var_name(var);
  301.             change = TRUE;
  302.             check_vars(var);
  303.         }
  304.         var[0] = val[0] = '\0';
  305.         actvar = TRUE;
  306.     }
  307.     else if (id == VARSLIST) /* Something in list selected */
  308.     {
  309.         if (ModifyList(gg, req, req->RWindow, class == GADGETUP) != 0 && *var)
  310.         {   /* New value selected from list or typed, ie new name. Switch to va
  311. lue gadget */
  312.             value vv;
  313.  
  314.             valpos = RemoveGList(req->RWindow, valg, 1);
  315.             varpos = RemoveGList(req->RWindow, varg, 1);
  316.             refresh = TRUE;
  317.             strip(var);
  318.  
  319.             if (!(vv = get_var_name(var)) || !decompile(vv, val, EXPRLEN)) val[
  320. 0] = '\0';
  321.             actval = TRUE;
  322.         }
  323.     }
  324.     else
  325.         return std_ghandler(gg, class, req, g);
  326.  
  327.     /* Handle requester services */
  328.     if (refresh)
  329.     {
  330.         AddGList(req->RWindow, varg, varpos, 1, req);
  331.         AddGList(req->RWindow, valg, valpos, 1, req);
  332.         RefreshGList(valg, req->RWindow, req, 1);
  333.         RefreshGList(varg, req->RWindow, req, 1);
  334.     }
  335.  
  336.     if (change) /* Variable list changed */
  337.         if (!ChangeList(var_info, &vars, req, req->RWindow))
  338.         {
  339.             EndRequest(req, req->RWindow);
  340.             /* Not enough memory ... */
  341.             actval = actvar = FALSE;
  342.        }
  343.  
  344.     if (actval) ActivateGadget(valg, req->RWindow, req);
  345.     if (actvar) ActivateGadget(varg, req->RWindow, req);
  346.     vars_saved = FALSE;
  347.  
  348.     return FALSE;
  349. }
  350.  
  351. /* Setup variables requester */
  352. void enter_vars(struct graph *g)
  353. {
  354.     struct Requester *req;
  355.     struct Memory *m;
  356.     struct Gadget *gl = NULL;
  357.  
  358.     if ((m = NewMemory()) &&
  359.         (req = InitReq(50, 20, 285, 126, m)) &&
  360.         SetReqBorder(req, 1, m) &&
  361.         AddIntuiText(&req->ReqText, "Edit variables", 86, 6, m) &&
  362.         (var_info = AddList(&gl, VARSLIST, "Variables", &vars, var, VARLEN, 0,
  363. RELVERIFY, 20, 20, 160, 80, TRUE, m)) &&
  364.         (valg = AddText(&gl, VARSLIST, "Value", FALSE, val, EXPRLEN, TRUE, 0, R
  365. ELVERIFY, 64, 110, 116, 10, TRUE, m)) &&
  366.         AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 200, 23, 65, 15, FALS
  367. E, m) &&
  368.         AddBox(&gl, VARSDEL, "Delete", 0, RELVERIFY, 200, 86, 65, 15, FALSE, m)
  369. )
  370.     {
  371.         var[0] = val[0] = '\0';
  372.         SetReqGadgets(req, gl);
  373.         DoRequest(req, g, vars_handler);
  374.         /* vars_handler called for every gadget event */
  375.     }
  376.     Free(m);
  377. }
  378.  
  379. /* Create a new graph */
  380. static struct graph *add_graph(struct graph *from)
  381. {
  382.     struct graph *g = new_graph(from);
  383.  
  384.     if (g) add_head(&graph_list, g);
  385.  
  386.     return g;
  387. }
  388.  
  389. /* Delete a graph, checking for save */
  390. static void remove_graph(struct graph *g)
  391. {
  392.     if (!g->saved) save_file(g);
  393.     remove(g);
  394.     delete_graph(g);
  395. }
  396.  
  397. /* Global initialisation */
  398. static int init(void)
  399. {
  400.     if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0))
  401.         if (DiskfontBase = (struct Library *)OpenLibrary("diskfont.library", 0)
  402. )
  403.             if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.
  404. library", 33))
  405.                 if (LayersBase = (struct LayersBase *)OpenLibrary("layers.libra
  406. ry", 33))
  407.                     if (ArpBase = (struct ArpBase *)OpenLibrary("arp.library",
  408. 0))
  409.                     {
  410.                         new_list(&graph_list);
  411.                         if (init_user() && init_grph() && add_graph(NULL))
  412.                             if (init_expr())
  413.                             {
  414.                                 init_context(&vars);
  415.                                 set_context(&vars);
  416.                                 return TRUE;
  417.                             }
  418.                             else alert(NULL, "Expression init failed", "No memo
  419. ry ?");
  420.                     }
  421.                     else alert(NULL, "arp.library required", NULL);
  422.                 else alert(NULL, "layers.library V1.2 required", NULL);
  423.             else alert(NULL, "intuition.library V1.2 required", NULL);
  424.         else alert(NULL, "diskfont.library required", NULL);
  425.     else alert(NULL, "graphics.library required", NULL);
  426.  
  427.     return FALSE;
  428. }
  429.  
  430. /* Free ALL resources ! */
  431. static void clean_up(void)
  432. {
  433.     struct graph *g, *next;
  434.  
  435.     cleanup_expr();
  436.     cleanup_grph();
  437.     cleanup_user();
  438.  
  439.     for (g = first(&graph_list); next = succ(g); g = next) remove_graph(g);
  440.  
  441.     if (ArpBase) CloseLibrary((struct Library *)ArpBase);
  442.     if (LayersBase) CloseLibrary((struct Library *)LayersBase);
  443.     if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  444.     if (DiskfontBase) CloseLibrary((struct Library *)DiskfontBase);
  445.     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
  446.  
  447. #ifdef DEBUG
  448.     TrackerExitReport();
  449. #endif
  450. }
  451.  
  452. void main(int argc, char **argv)
  453. {
  454.     struct cmd cmd;
  455.     int done = FALSE;
  456.  
  457.     if (init())
  458.         do
  459.             switch ((cmd = next_command()).command)
  460.             {
  461.                 case close:
  462.                     done = succ(succ(first(&graph_list))) == NULL; /* one graph
  463.  left ? */
  464.                     if (done && !vars_saved) save_variables(cmd.g);
  465.                     remove_graph(cmd.g);
  466.                     break;
  467.                 case _new_graph:
  468.                     add_graph(cmd.g);
  469.                     break;
  470.                 case _load_graph:
  471.                     load_file(cmd.g);
  472.                     break;
  473.                 case _save_graph:
  474.                     save_file(cmd.g);
  475.                     break;
  476.                 case print_graph:
  477.                     prt_graph(cmd.g);
  478.                     break;
  479.                 case iff_graph:
  480.                     iff_todisk(cmd.g);
  481.                     break;
  482.                 case save_vars:
  483.                     save_variables(cmd.g);
  484.                     break;
  485.                 case load_vars:
  486.                     load_variables(cmd.g);
  487.                     break;
  488.                 case quit:
  489.                     if (!vars_saved) save_variables(cmd.g);
  490.                     done = TRUE;
  491.                     break;
  492.                 case add_function:
  493.                     select_object(cmd.g, add_object(cmd.g, new_function(cmd.g))
  494. );
  495.                     break;
  496.                 case add_label:
  497.                     add_object(cmd.g, (struct object *)new_label(cmd.g, cmd.dat
  498. a.pt.x, cmd.data.pt.y));
  499.                     break;
  500.                 case del_object:
  501.                     remove_object(cmd.g, cmd.data.o);
  502.                     break;
  503.                 case limits:
  504.                     enter_limits(cmd.g);
  505.                     break;
  506.                 case axes:
  507.                     enter_axes(cmd.g);
  508.                     break;
  509.                 case zoom:
  510.                     zoom_in(cmd.g, cmd.data.zoom_in.x0, cmd.data.zoom_in.y0, cm
  511. d.data.zoom_in.x1, cmd.data.zoom_in.y1);
  512.                     break;
  513.                 case zoom_out:
  514.                     zoom_factor(cmd.g, cmd.data.zoom_out);
  515.                     break;
  516.                 case center:
  517.                     center_graph(cmd.g, cmd.data.pt.x, cmd.data.pt.y);
  518.                     break;
  519.                 case edit:
  520.                     {
  521.                         struct Region *ref;
  522.  
  523.                         if (cmd.data.o->edit(cmd.data.o, &ref))
  524.                         {
  525.                             cmd.g->saved = FALSE;
  526.                             refresh_graph(cmd.g, TRUE, ref);
  527.                         }
  528.                     }
  529.                     break;
  530.                 case improve:
  531.                     refresh_graph(cmd.g, TRUE, cmd.data.o->improve(cmd.data.o))
  532. ;
  533.                     break;
  534.                 case edit_vars:
  535.                     enter_vars(cmd.g);
  536.                     draw_all();
  537.                     break;
  538.             }
  539.         while (!done);
  540.  
  541.     clean_up();
  542. }
  543.  
  544.